use crate::dlx;
use ndarray::Array2;
use clap::ValueEnum;
use rand::prelude::*;

const SIZE: usize = 9;
const BOX_SIZE: usize = 3;

#[derive(Debug, Clone)]
pub struct Sudoku {
    grid: Array2<u8>,  // 使用ndarray的二维数组替代原生数组
}

impl Sudoku {
    /// 创建新的空数独
    pub fn new() -> Self {
        Sudoku {
            grid: Array2::zeros((SIZE, SIZE)),
        }
    }
    
    /// 打印数独到控制台
    pub fn print(&self) {
        for i in 0..SIZE {
            if i % BOX_SIZE == 0 && i != 0 {
                println!("------+-------+------");
            }
            
            for j in 0..SIZE {
                if j % BOX_SIZE == 0 && j != 0 {
                    print!("| ");
                }
                
                if self.grid[[i, j]] == 0 {
                    print!(". ");
                } else {
                    print!("{} ", self.grid[[i, j]]);
                }
            }
            println!();
        }
    }

    /// 从现有数组创建数独
    pub fn from_grid(grid: [[u8; SIZE]; SIZE]) -> Self {
        Sudoku {
            grid: Array2::from_shape_vec((SIZE, SIZE), grid.into_iter().flatten().collect()).unwrap()
        }
    }

    pub fn generate(&mut self, difficulty: Difficulty) {
        // 1. 生成一个完整解法的数独
        self.grid = Array2::zeros((SIZE, SIZE));
        
        // 2. 随机填充对角线上的3x3方块（确保每个方块有效）
        self.fill_diagonal_boxes();
        
        // 3. 使用DLX算法解决剩余部分
        self.solve();
        
        // 4. 根据难度级别挖空
        let cells_to_remove = match difficulty {
            Difficulty::Easy => 30..40,
            Difficulty::Medium => 40..50,
            Difficulty::Hard => 50..60,
            Difficulty::Expert => 60..70,
        };
        
        self.remove_cells(cells_to_remove);
    }
    
    fn fill_diagonal_boxes(&mut self) {
        for box_idx in 0..BOX_SIZE {
            let start_row = box_idx * BOX_SIZE;
            let start_col = box_idx * BOX_SIZE;
            
            let mut nums: Vec<u8> = (1..=SIZE as u8).collect();
            nums.shuffle(&mut rand::rng());
            
            for i in 0..BOX_SIZE {
                for j in 0..BOX_SIZE {
                    self.grid[(start_row + i, start_col + j)] = nums[i * BOX_SIZE + j];
                }
            }
        }
    }
    
    fn remove_cells(&mut self, range: std::ops::Range<usize>) {
        use rand::seq::SliceRandom;
        
        let cells_to_remove = rand::rng().random_range(range);
        let mut positions: Vec<(usize, usize)> = (0..SIZE)
            .flat_map(|row| (0..SIZE).map(move |col| (row, col)))
            .collect();
            
        positions.shuffle(&mut rand::rng());
        
        for &(row, col) in positions.iter().take(cells_to_remove) {
            self.grid[(row, col)] = 0;
        }
    }

    pub fn solve(&mut self) -> bool {
        // Convert Sudoku to exact cover problem and use DLX to solve
        let mut dlx = self.build_dlx_matrix();
        // 由于 solve 方法是私有的，需要确保 dlx 模块提供一个公共方法来调用 solve。
        // 假设 dlx 模块提供了一个公共的 wrapper 方法 public_solve
        if dlx.solve() {
            self.apply_solution(&dlx.solution);
            true
        } else {
            false
        }
    }

    /// 验证数独完整性和有效性
    /// 返回Result类型，包含详细的错误信息
    pub fn validate(&self) -> Result<(), String> {
        // 检查行有效性
        for row in 0..9 {
            if !self.is_row_valid(row) {
                return Err(format!("第{}行存在重复数字", row + 1));
            }
        }
        
        // 检查列有效性
        for col in 0..9 {
            if !self.is_col_valid(col) {
                return Err(format!("第{}列存在重复数字", col + 1));
            }
        }
        
        // 检查宫格有效性
        for box_row in 0..3 {
            for box_col in 0..3 {
                if !self.is_box_valid(box_row, box_col) {
                    return Err(format!("第{}宫格存在重复数字", box_row * 3 + box_col + 1));
                }
            }
        }
        
        // 检查是否有空单元格
        if self.grid.iter().any(|&cell| cell == 0) {
            return Err("数独包含未填写的空单元格".to_string());
        }
        
        Ok(())
    }
    
    /// 检查指定行是否有效
    fn is_row_valid(&self, row: usize) -> bool {
        let mut seen = [false; 10];
        for col in 0..SIZE {
            let num = self.grid[[row, col]];
            if num != 0 && seen[num as usize] {
                return false;
            }
            seen[num as usize] = true;
        }
        true
    }
    
    /// 检查指定列是否有效
    fn is_col_valid(&self, col: usize) -> bool {
        let mut seen = [false; 10];
        for row in 0..SIZE {
            let num = self.grid[[row, col]];
            if num != 0 && seen[num as usize] {
                return false;
            }
            seen[num as usize] = true;
        }
        true
    }
    
    /// 检查指定3x3宫格是否有效
    fn is_box_valid(&self, box_row: usize, box_col: usize) -> bool {
        let mut seen = [false; 10];
        for r in 0..BOX_SIZE {
            for c in 0..BOX_SIZE {
                let row = box_row * BOX_SIZE + r;
                let col = box_col * BOX_SIZE + c;
                let num = self.grid[[row, col]];
                if num != 0 && seen[num as usize] {
                    return false;
                }
                seen[num as usize] = true;
            }
        }
        true
    }

    fn build_dlx_matrix(&self) -> dlx::DLX {
        // Sudoku constraints: 
        // 1. Each cell must contain exactly one number
        // 2. Each row must contain each number exactly once
        // 3. Each column must contain each number exactly once
        // 4. Each box must contain each number exactly once
        
        // Total constraints: 4 * 9 * 9 = 324
        // Total possibilities: 9 * 9 * 9 = 729 (each cell can be 1-9)
        
        let mut dlx = dlx::DLX::new(729, 324);
        
        for row in 0..SIZE {
            for col in 0..SIZE {
                let num = self.grid[(row, col)];
                
                if num == 0 {
                    // Empty cell - add all possible numbers
                    for n in 1..=SIZE {
                        self.add_dlx_row(&mut dlx, row, col, n as u8);
                    }
                } else {
                    // Pre-filled cell - only add the given number
                    self.add_dlx_row(&mut dlx, row, col, num);
                }
            }
        }
        
        dlx
    }
    
    fn add_dlx_row(&self, dlx: &mut dlx::DLX, row: usize, col: usize, num: u8) {
        // Calculate constraint positions
        let cell_constraint = row * SIZE + col;
        let row_constraint = SIZE * SIZE + row * SIZE + (num - 1) as usize;
        let col_constraint = 2 * SIZE * SIZE + col * SIZE + (num - 1) as usize;
        let box_constraint = 3 * SIZE * SIZE + 
            (row / BOX_SIZE * BOX_SIZE + col / BOX_SIZE) * SIZE + 
            (num - 1) as usize;
        
        // Add row with these 4 constraints
        dlx.add_row(
            row * SIZE * SIZE + col * SIZE + (num - 1) as usize,
            &[cell_constraint + 1, row_constraint + 1, col_constraint + 1, box_constraint + 1]
        );
    }

    fn apply_solution(&mut self, solution: &[usize]) {
        for &row_idx in solution {
            let num = (row_idx % SIZE + 1) as u8;
            let cell_idx = row_idx / SIZE;
            let col = cell_idx % SIZE;
            let row = cell_idx / SIZE;
            
            self.grid[(row, col)] = num;
        }
    }
    
    // 实现从输入数据加载数独的方法
    pub(crate) fn load_from_data(&mut self, input_data: Vec<Vec<u8>>) -> Result<(), String> {
        // 检查输入数据的行数是否符合数独大小
        if input_data.len() != SIZE {
            return Err(format!("输入数据的行数必须为 {}, 但实际为 {}", SIZE, input_data.len()));
        }

        // 检查每一行的列数是否符合数独大小
        for (i, row) in input_data.iter().enumerate() {
            if row.len() != SIZE {
                return Err(format!("第 {} 行的列数必须为 {}, 但实际为 {}", i + 1, SIZE, row.len()));
            }
        }

        // 将输入数据转换为一维向量
        let flat_data: Vec<u8> = input_data.into_iter().flatten().collect();

        // 尝试将一维向量转换为 Array2
        match Array2::from_shape_vec((SIZE, SIZE), flat_data) {
            Ok(new_grid) => {
                self.grid = new_grid;
                Ok(())
            }
            Err(_) => Err("无法将输入数据转换为有效的数独网格".to_string()),
        }
    }
}

#[derive(Debug, Clone, ValueEnum)]
pub enum Difficulty {
    Easy,
    Medium,
    Hard,
    Expert,
}